﻿#pragma once

#include "Plugin/Invoker.h"

#include <string>

class PluginManager;

class IPlugin
{
public:
  IPlugin() {};
  virtual ~IPlugin() {};

  virtual std::string GetName() { return "UnknownPlugin"; };

  template <typename R = void, typename... Args>
  R Call(const std::string &funcName, Args &&...args)
  {
    auto params = ParamPacker::Pack(std::forward<Args>(args)...);

    auto name = GetName() + "." + funcName;
    if (!container.fnMap.contains(name))
    {
      if constexpr (!std::is_same_v<R, void>)
        return {};
      else
        return;      
    }
    auto func = container.fnMap.at(name);

    if constexpr (!std::is_same_v<R, void>)
    {
      if constexpr (std::is_class_v<R>) { // 处理返回对象类型
        return ParamPacker::Unpack<std::tuple<R>>(func(params));
      } else { // 处理基本类型
        return ParamPacker::UnpackSingle<R>(func(params));
      }
    }
    else
    {
      func(params);
    }
  }

  CallableContainer container;

protected:
  PluginManager *pluginManager = nullptr;

  friend class PluginManager;
};
